// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE-BSD file. See the AUTHORS file for names of contributors.

// SPDX-License-Identifier: Apache-2.0
// Copyright 2020, Intel Corporation

// See port_example.h for documentation for the following types/functions.

#ifndef STORAGE_LEVELDB_PORT_PORT_POSIX_H_
#define STORAGE_LEVELDB_PORT_PORT_POSIX_H_

#undef PLATFORM_IS_LITTLE_ENDIAN
#if defined(__APPLE__)
#include <machine/endian.h>
#if defined(__DARWIN_LITTLE_ENDIAN) && defined(__DARWIN_BYTE_ORDER)
#define PLATFORM_IS_LITTLE_ENDIAN (__DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN)
#endif
#elif defined(OS_SOLARIS)
#include <sys/isa_defs.h>
#ifdef _LITTLE_ENDIAN
#define PLATFORM_IS_LITTLE_ENDIAN true
#else
#define PLATFORM_IS_LITTLE_ENDIAN false
#endif
#elif defined(OS_FREEBSD) || defined(OS_OPENBSD) || defined(OS_NETBSD) || defined(OS_DRAGONFLYBSD)
#include <sys/endian.h>
#include <sys/types.h>
#define PLATFORM_IS_LITTLE_ENDIAN (_BYTE_ORDER == _LITTLE_ENDIAN)
#elif defined(OS_HPUX)
#define PLATFORM_IS_LITTLE_ENDIAN false
#elif defined(OS_ANDROID)
// Due to a bug in the NDK x86 <sys/endian.h> definition,
// _BYTE_ORDER must be used instead of __BYTE_ORDER on Android.
// See http://code.google.com/p/android/issues/detail?id=39824
#include <endian.h>
#define PLATFORM_IS_LITTLE_ENDIAN (_BYTE_ORDER == _LITTLE_ENDIAN)
#else
#include <endian.h>
#endif

#include <pthread.h>
#if defined(HAVE_CRC32C)
#include <crc32c/crc32c.h>
#endif // defined(HAVE_CRC32C)
#ifdef HAVE_SNAPPY
#include <snappy.h>
#endif // defined(HAVE_SNAPPY)
#include "port/atomic_pointer.h"
#include <stdint.h>
#include <string>

#ifndef PLATFORM_IS_LITTLE_ENDIAN
#define PLATFORM_IS_LITTLE_ENDIAN (__BYTE_ORDER == __LITTLE_ENDIAN)
#endif

#if defined(__APPLE__) || defined(OS_FREEBSD) || defined(OS_OPENBSD) || defined(OS_DRAGONFLYBSD)
// Use fsync() on platforms without fdatasync()
#define fdatasync fsync
#endif

#if defined(OS_ANDROID) && __ANDROID_API__ < 9
// fdatasync() was only introduced in API level 9 on Android. Use fsync()
// when targetting older platforms.
#define fdatasync fsync
#endif

namespace leveldb
{
namespace port
{

static const bool kLittleEndian = PLATFORM_IS_LITTLE_ENDIAN;
#undef PLATFORM_IS_LITTLE_ENDIAN

class CondVar;

class Mutex {
public:
	Mutex();
	~Mutex();

	void Lock();
	void Unlock();
	void AssertHeld()
	{
	}

private:
	friend class CondVar;
	pthread_mutex_t mu_;

	// No copying
	Mutex(const Mutex &);
	void operator=(const Mutex &);
};

class CondVar {
public:
	explicit CondVar(Mutex *mu);
	~CondVar();
	void Wait();
	void Signal();
	void SignalAll();

private:
	pthread_cond_t cv_;
	Mutex *mu_;
};

typedef pthread_once_t OnceType;
#define LEVELDB_ONCE_INIT PTHREAD_ONCE_INIT
extern void InitOnce(OnceType *once, void (*initializer)());

inline bool Snappy_Compress(const char *input, size_t length, ::std::string *output)
{
#ifdef HAVE_SNAPPY
	output->resize(snappy::MaxCompressedLength(length));
	size_t outlen;
	snappy::RawCompress(input, length, &(*output)[0], &outlen);
	output->resize(outlen);
	return true;
#endif // defined(HAVE_SNAPPY)

	return false;
}

inline bool Snappy_GetUncompressedLength(const char *input, size_t length, size_t *result)
{
#ifdef HAVE_SNAPPY
	return snappy::GetUncompressedLength(input, length, result);
#else
	return false;
#endif // defined(HAVE_SNAPPY)
}

inline bool Snappy_Uncompress(const char *input, size_t length, char *output)
{
#ifdef HAVE_SNAPPY
	return snappy::RawUncompress(input, length, output);
#else
	return false;
#endif // defined(HAVE_SNAPPY)
}

inline bool GetHeapProfile(void (*func)(void *, const char *, int), void *arg)
{
	return false;
}

inline uint32_t AcceleratedCRC32C(uint32_t crc, const char *buf, size_t size)
{
#if defined(HAVE_CRC32C)
	return ::crc32c::Extend(crc, reinterpret_cast<const uint8_t *>(buf), size);
#else
	return 0;
#endif // defined(HAVE_CRC32C)
}

} // namespace port
} // namespace leveldb

#endif // STORAGE_LEVELDB_PORT_PORT_POSIX_H_
